package ifo;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;

import jxl.Workbook;
import jxl.WorkbookSettings;

public class CommandLineOptions {
	
	private long startTime = 0;
	private String rawOptions = "";
	private boolean isValid = false;

	private String workingDir = "";
	private ArrayList<File> allFiles, pendingFiles, finishedFiles, faultyFiles;
	private int fileCount = 0;
	private int pendingFileCount = 0;
	
	private boolean interactiveMode = false;
	
	private boolean verboseMode = false;
	private boolean veryVerboseMode = false;
	private boolean quietMode = false;
	
	private boolean displayHelp = false;
	private boolean displayWB = false;
	private boolean displayWS = false;

	private boolean doSchema1 = false;
	private boolean doSchema2 = false;
	private boolean doSchema3 = false;
	
	private boolean trimData = false;
	private boolean useDict = false;
	
	private boolean useWhitelist = false;
	
	public final static String enclosedBy ="\"|";
	public final static String recDelimiter =";|";
	
	//private String outputFormat = ""+enclosedBy+"%FPath%"+enclosedBy+"\t"+enclosedBy+"%FileName%"+enclosedBy+"\t"+enclosedBy+"%Title%"+enclosedBy+"\t"+enclosedBy+"%WsTitle%"+enclosedBy+"\t"+enclosedBy+"%DimensionA%"+enclosedBy+"\t"+enclosedBy+"%DimensionB%"+enclosedBy+"\t"+enclosedBy+"%Value%"+enclosedBy+";";
	private String outputFormat = enclosedBy+"%FileName%"  +enclosedBy+"\t"
	                             +enclosedBy+"%Title%"     +enclosedBy+"\t"
			                     +enclosedBy+"%WsTitle%"   +enclosedBy+"\t"
	                             +enclosedBy+"%DimensionA%"+enclosedBy+"\t"
			                     +enclosedBy+"%DimensionB%"+enclosedBy+"\t"
	                             +enclosedBy+"%Value%"     +enclosedBy+"\t"
	                             +enclosedBy+"%Precision%" +enclosedBy+"\t"
	                             +enclosedBy+"%Column%"    +enclosedBy+"\t"
	                             +recDelimiter;
	
	private String[][] arguments = {
			{ "--count-workbooks", "-C", " Only return the number of excel files in the given directory." },
			{ "--count-worksheets", "-c", "Only return the number of worksheets in the given directory." },
			{ "--dictionary", "-d", "      Use the hard coded internal dictionaries to perform country list and files detection"},
			{ "--help", "-h", "            Display this help." },
			{ "--interactive", "-i", "     Start in interactive mode. (confirm each sheet manually)"},
			{ "--output-format", "-o", "   \"FORMAT\"\n" +
			  "                             Redefine the output format.\n" +
			  "                             Default is \"%Title%\", \"%DimensionA%\", \"%DimensionB%\", \"%Value%\";\n" +
			  "                             Further placeholders:\n" +
			  "                             %Description%        Anything that doesn't fit any category\n" +
			  "                             %WsTitle%            Current worksheet title\n" +
			  "                             %FilePath%           Current file path + filename\n" +
			  "                             %FileName%           Current file name\n" +
			  "                             %FPath%              Current file path\n" +
			  "                             %Footnotes%          Current worksheet's footnotes\n" +
			  "                             %WorksheetNr%        Current worksheet"},
			{ "--quiet", "-q", "           Quiet mode, don't print out anything."},
			{ "--schema1", "-1", "         Parse excel sheets conforming to schema01."},
			{ "--schema2", "-2", "         Parse excel sheets conforming to schema02."},
			{ "--schema3", "-3", "         Parse excel sheets conforming to schema03."},
			{ "--trim", "-t", "            Trim output data. (remove preceeding and trailing whitespace)"},
			{ "--verbose", "-v", "         Turn on detailed output. (A second v gives more.)"},
			{ "--whitelist", "-w", "       Turn on whitelist. (Otherwise use all files.)"	}
	};
	
	@SuppressWarnings("unchecked")
	public CommandLineOptions(String[] argv) {
		startTime = System.currentTimeMillis();
		printHeader();
		if (argv.length < 1) {
			System.out.println("You need to specify a path to a directory or file to work with.");
			printUsage();
			return;
		}
		if (argv.length == 1) {
			if (argv[0].compareToIgnoreCase("-h") == 0 || argv[0].compareToIgnoreCase("--help") == 0) {
				printUsage();
				return;
			}
			
		}
		try {
			allFiles = (ArrayList<File>) FileListing.getFileListing(new File(argv[0]));
		} catch (FileNotFoundException e) {
			System.out.println("Could not read path: " + argv[0]);
			return;
		}
		
		finishedFiles = new ArrayList<File>();
		faultyFiles = new ArrayList<File>();
		pendingFiles = (ArrayList<File>) allFiles.clone();
		fileCount = allFiles.toArray().length;
		pendingFileCount = pendingFiles.toArray().length;
		
		retrieveOptionsFromArguments(argv);
		
		if (displayHelp) {
			printUsage();
		}
		if (displayWB) {
			System.out.println("Found " + fileCount + " excel workbooks.");
		}
		if (displayWS) {
			System.out.println("\nFound " + getWorksheetCount() + " excel worksheets.");
		}

		if (displayWS || displayWB || displayHelp) return;
		
		if (quietMode && interactiveMode) {
			System.out.println("Option clash for -q and -i. Could not start.");
			return;
		}
		
		if (verboseMode) {
			System.out.println("Starting in VERBOSE mode ...");
		}
		
		if (!doSchema1 && !doSchema2 && !doSchema3) {
			System.out.println("No schema detected, assuming schema01 ...");
			doSchema1 = true;
		}
		
		isValid = true;
	}
	
	private void retrieveOptionsFromArguments(String[] argv) {
		String tempOptions = "";
		for (int i = 1; i < argv.length; i++) {
			tempOptions = tempOptions + argv[i];
			if (argv[i].compareTo("-o") == 0 || argv[i].compareTo("--output-format") == 0) {
				if (i + 1 >= argv.length) {
					System.out.println("Parameter -o needs to be followed by a format string.");
				} else {
					outputFormat = argv[i + 1];
					argv[i + 1] = "";
				}
			}
		}
		for (int i = 0; i < arguments.length; i++) {
			tempOptions = tempOptions.replaceAll(arguments[i][0], arguments[i][1]);
		}
		tempOptions = tempOptions.replaceAll("-", "");
		tempOptions = tempOptions.replaceAll(" ", "");
		
		rawOptions = tempOptions;
		
		if (rawOptions.contains("h")) displayHelp = true;
		if (rawOptions.contains("t")) trimData = true;
		if (rawOptions.contains("d")) useDict = true;
		if (rawOptions.contains("w")) useWhitelist = true;
		if (rawOptions.contains("i")) interactiveMode = true;
		if (rawOptions.contains("v")) verboseMode = true;
		if (rawOptions.contains("vv")) veryVerboseMode = true;
		if (rawOptions.contains("q")) quietMode = true;
		if (rawOptions.contains("C")) displayWB = true;
		if (rawOptions.contains("c")) displayWS = true;
		if (rawOptions.contains("1")) doSchema1 = true;
		if (rawOptions.contains("2")) doSchema2 = true;
		if (rawOptions.contains("3")) doSchema3 = true;
	}
	private int getWorksheetCount() {
		int count = 0;
		int len = allFiles.toArray().length;
		
		WorkbookSettings wbs = new WorkbookSettings();
		wbs.setSuppressWarnings(true);
		for (int i = 0; i < len; i++) {
			if (i % 10 == 0)
				System.out.print("Calculating number of worksheets ... " + (int)((float)i / len * 100.0 + 0.5) + " %\r");
			try {
				count += Workbook.getWorkbook(allFiles.get(i), wbs).getNumberOfSheets();
			} catch (Exception e) {	}
		}
		return count;
	}
	
	public File dequeue() {
		if (!pendingFiles.isEmpty()) {
			return pendingFiles.remove(0);
		} else {
			return new File("");
		}
	}

	public void enqueueSuccess(File f) {
		finishedFiles.add(f);
		return;
	}
	
	public void enqueueFail(File f) {
		faultyFiles.add(f);
		return;
	}
	
	public void copyFailToPending() {
		pendingFiles.removeAll(pendingFiles);
		pendingFiles.addAll(faultyFiles);
		faultyFiles.removeAll(faultyFiles);
		pendingFileCount = pendingFiles.toArray().length;
	}
	/* Getters and setters */
	public boolean trimData() {
		return trimData;
	}
	public String getOutputFormat() {
		return outputFormat;
	}
	public boolean getInteractive() {
		return interactiveMode;
	}
	public boolean isVerbose() {
		return verboseMode;
	}
	public boolean isVeryVerbose() {
		return veryVerboseMode;
	}
	public boolean isQuiet() {
		return quietMode;
	}
	public boolean getSchema1() {
		return doSchema1;
	}
	public boolean getSchema2() {
		return doSchema2;
	}	
	public boolean getSchema3() {
		return doSchema3;
	}
	public boolean getValid() {
		return isValid;
	}
	public int getFileCount() {
		return fileCount;
	}
	public int getPendingFileCount() {
		return pendingFileCount;
	}
	public int getFaultyFileCount() {
		return faultyFiles.toArray().length;
	}
	public boolean getDictState() {
		return useDict;
	}
	public boolean getWhitelist() {
		return useWhitelist;
	}	
	public int getFinishedLength() {
		return finishedFiles.size();
	}
	public String getWorkingDir() {
		return workingDir;
	}
	public void setFinishedFiles(ArrayList<File> finishedFiles) {
		this.finishedFiles = finishedFiles;
	}
	public ArrayList<File> getFinishedFiles() {
		return finishedFiles;
	}
	private void printHeader() {
		System.out.println("=========================================================================");
		System.out.println("8888888b. 8888888 .d8888b.  8888888888 ");
		System.out.println("888  \"Y88b  888  d88P  Y88b 888        ");
		System.out.println("888    888  888  888    888 888        ");
		System.out.println("888    888  888  888        8888888    ");
		System.out.println("888    888  888  888        888           _ __   __ _ _ __ ___  ___ _ __ ");
		System.out.println("888    888  888  888    888 888          | '_ \\ / _` | '__/ __|/ _ \\ '__|");
		System.out.println("888  .d88P  888  Y88b  d88P 888          | |_) | (_| | |  \\__ \\  __/ |   ");
		System.out.println("8888888P\" 8888888 \"Y8888P\"  8888888888   | .__/ \\__,_|_|  |___/\\___|_|  ");
		System.out.println("                                         | |");
		System.out.println("                                         |_|");                         
		System.out.println("is here to save the day! ================================================\n");
	}
	public long getStartTime() {
		return startTime;
	}
	private void printUsage() {
		System.out.println("Usage:");
		System.out.println("dice_parser WORKINGDIR OPTIONS\n");
		System.out.println("Where");
		System.out.println("  WORKINGDIR is a path to an existent directory containing"); 
		System.out.println("             excel sheets either directly or in subdirectories.");
		System.out.println("  OPTIONS    is one of the following:");
		for (int i = 0; i < arguments.length; i++) {
			System.out.println("  " + arguments[i][0] + ", " + arguments[i][1] + "     " + arguments[i][2]);
		}
		System.out.println("");
		System.out.println("All data is written to outfiles which are automatically created.");
		System.out.println("");
		System.out.println("=========================================================================");
	}
}
